package com.lmco.ws101;

import com.sun.ws.management.addressing.DestinationUnreachableFault;
import com.sun.ws.management.framework.Utilities;
import com.sun.ws.management.framework.transfer.TransferSupport;
import com.sun.ws.management.AlreadyExistsFault;
import com.sun.ws.management.InternalErrorFault;
import com.sun.ws.management.InvalidSelectorsFault;
import com.sun.ws.management.Management;
import com.sun.ws.management.server.HandlerContext;
import com.sun.ws.management.transfer.InvalidRepresentationFault;
import com.sun.ws.management.transfer.TransferExtensions;

import com.lmco.ws101.restaurant.jaxb.ObjectFactory;
import com.lmco.ws101.restaurant.jaxb.RestaurantRatingType;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;

import org.dmtf.schemas.wbem.wsman._1.wsman.SelectorType;
import org.xmlsoap.schemas.ws._2004._08.addressing.EndpointReferenceType;

public class RestaurantratingresourceHandler extends TransferSupport {

    // Log for logging messages
    private final Logger log;
    private final ObjectFactory resourceFactory;
    private final static QName QNAME = new QName("http://ws101.lmco.com/restaurant", "restaurantRating");
    private static Map<String, RestaurantRatingType> ratings = new HashMap<String, RestaurantRatingType>();
    
    public RestaurantratingresourceHandler() {
        super();
        
        // Initialize our member variables
        log = Logger.getLogger(RestaurantratingresourceHandler.class.getName());
        resourceFactory = new ObjectFactory();
    } 
    
    public static String getKey(String name, String city) {
        return name + "::" + city;
    }
    
    public static String getSelectorByName(String selectorName, Management request) 
                throws InternalErrorFault, JAXBException, SOAPException {
        Set<SelectorType> selectors = request.getSelectors();
        SelectorType selector = Utilities.getSelectorByName(selectorName, selectors);

        if (selector == null || selector.getContent().size() == 0) {
            throw new InvalidSelectorsFault(InvalidSelectorsFault.Detail.INSUFFICIENT_SELECTORS);
        }

        return (String) selector.getContent().get(0);
    }

    public void Get( HandlerContext context, Management request, Management response ) {
        try {
            TransferExtensions xferResponse = new TransferExtensions(response);

            String name = getSelectorByName("name", request);
            String city = getSelectorByName("city", request);
            String key =  getKey(name, city);
            RestaurantRatingType rating = ratings.get(key);
            
            if (rating == null) {
                throw new DestinationUnreachableFault("The SelectorSet failed to identify an existing resource");
            }
            
            JAXBElement<RestaurantRatingType> element = resourceFactory.createRestaurantRating(rating);
            xferResponse.setGetResponse(element);
        } catch (JAXBException e) {
            log.severe(e.getMessage());
            throw new InternalErrorFault(e);
        } catch (SOAPException e) {
            log.severe(e.getMessage());
            throw new InternalErrorFault(e);
        }
    }

    public void Create( HandlerContext context, Management request, Management response ) {
        try {
            // Get the resource passed in the body
            TransferExtensions xferRequest = new TransferExtensions(request);
            TransferExtensions xferResponse = new TransferExtensions(response);
            Object element = xferRequest.getResource(QNAME);
            
            if (element != null) {
            	@SuppressWarnings("unchecked")
                JAXBElement<RestaurantRatingType> jaxbElement = (JAXBElement<RestaurantRatingType>) element;
                RestaurantRatingType rating = jaxbElement.getValue();
                String name = rating.getRestaurant().getName();
                String city = rating.getRestaurant().getCity();
                String key =  getKey(name, city);
                
                // Make sure it doesn't already exist
                if (ratings.containsKey(key)) {
                    throw new AlreadyExistsFault();
                }

                // Store it
                ratings.put(key, rating);

                // Define a selector
                HashMap<String, String> selectors = new HashMap<String, String>();
                selectors.put("name", name);
                selectors.put("city", city);
                EndpointReferenceType epr = TransferExtensions.createEndpointReference(
                        request.getTo(), request.getResourceURI(), selectors);
                xferResponse.setCreateResponse(epr);
            } else {
                throw new InvalidRepresentationFault(InvalidRepresentationFault.Detail.MISSING_VALUES);
            }
        } catch (JAXBException e) {
            log.severe(e.getMessage());
            throw new InternalErrorFault(e);
        } catch (SOAPException e) {
            log.severe(e.getMessage());
            throw new InternalErrorFault(e);
        }
    }

    public void Put( HandlerContext context, Management request, Management response ) {
        try {
            // Get the resource passed in the body
            TransferExtensions xferRequest = new TransferExtensions(request);
            TransferExtensions xferResponse = new TransferExtensions(response);
            Object element = xferRequest.getResource(QNAME);
            
            if (element != null) {
            	@SuppressWarnings("unchecked")
                JAXBElement<RestaurantRatingType> jaxbElement = (JAXBElement<RestaurantRatingType>) element;
                RestaurantRatingType rating = jaxbElement.getValue();

                String name = getSelectorByName("name", request);
                String city = getSelectorByName("city", request);
                String key =  getKey(name, city);
                
                // Update the resource
                if (ratings.containsKey(key)) {
                    ratings.put(key, rating);
                    xferResponse.setPutResponse(jaxbElement);
                } else {
                    throw new DestinationUnreachableFault("The SelectorSet failed to identify an existing resource");
                }
            } else {
                throw new InvalidRepresentationFault(InvalidRepresentationFault.Detail.MISSING_VALUES);
            }
        } catch (JAXBException e) {
            log.severe(e.getMessage());
            throw new InternalErrorFault(e);
        } catch (SOAPException e) {
            log.severe(e.getMessage());
            throw new InternalErrorFault(e);
        }
   }

    public void Delete( HandlerContext context, Management request, Management response ) {
        try {
            String name = getSelectorByName("name", request);
            String city = getSelectorByName("city", request);
            String key =  getKey(name, city);
            ratings.remove(key);

            TransferExtensions xferResponse = new TransferExtensions(response);
            xferResponse.setDeleteResponse();
        } catch (JAXBException e) {
            log.severe(e.getMessage());
            throw new InternalErrorFault(e);
        } catch (SOAPException e) {
            log.severe(e.getMessage());
            throw new InternalErrorFault(e);
        }
    }
}
